#include <algorithm>
#include <cctype>
#include <cstdio>

typedef long long ll;

const int N = 1e5 + 5, bit = 19;

template <typename T>
inline T& read(T& x) {
  x = 0;
  bool f = false;
  short ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') f = true;
    ch = getchar();
  }
  while (isdigit(ch)) x = x * 10 + (ch ^ '0'), ch = getchar();
  if (f) x = -x;
  return x;
}

int n;
int lg[N * 2], q[2][N], cnt[2];
bool typ[N];
ll ans;
ll nw[N];
#define cmi(u, v) (dep[u] < dep[v] ? u : v)

struct Graph {
  struct Edge {
    int v, nxt;
    ll w;
  };
  Edge e[N << 2];

  int e_cnt = 1, heads[N << 1];

  inline void add(int u, int v, ll w) {
    e[++e_cnt].v = v, e[e_cnt].nxt = heads[u], heads[u] = e_cnt, e[e_cnt].w = w;
    e[++e_cnt].v = u, e[e_cnt].nxt = heads[v], heads[v] = e_cnt, e[e_cnt].w = w;
  }
};

namespace Tr3 {

Graph G;

int cnt;
int st[bit][N * 2], dfn[N], dep[N];
ll dis[N];

void dfs(int u, int fa) {
  st[0][dfn[u] = ++cnt] = u;
  nw[u] += dis[u];
  for (int i = G.heads[u], v; i; i = G.e[i].nxt)
    if ((v = G.e[i].v) != fa) {
      dis[v] = dis[u] + G.e[i].w, dep[v] = dep[u] + 1;
      dfs(v, u);
      st[0][++cnt] = u;
    }
}

inline void pre() {
  for (int k = 1, j = 1; k < cnt; k <<= 1, ++j)
    for (int i = 1; i + k <= cnt; ++i) st[j][i] = cmi(st[j - 1][i], st[j - 1][i + k]);
}

inline int getLca(int u, int v) {
  u = dfn[u], v = dfn[v];
  if (v < u) std::swap(u, v);
  int k = lg[v - u + 1];
  return cmi(st[k][u], st[k][v - (1 << k) + 1]);
}

inline ll getDis(int u, int v) { return nw[u] + nw[v] - (dis[getLca(u, v)] << 1); }

}  // namespace Tr3

namespace Tr2 {

Graph G;

int tp, tot, df, cnt;
int sta[N], st[bit][N * 2], dfn[N], dep[N], node[N * 2], dfi[N], dfo[N];
bool key[N];
ll dis[N];
#define cd(u, v) (Tr3::getDis(u, v))

struct Data {
  int u, v;
  ll dis;
  Data() : u(0), v(0), dis(0) {}
  Data(int u, int v) : u(u), v(v), dis(cd(u, v)) {}
  Data(int u, int v, ll dis) : u(u), v(v), dis(dis) {}
  inline bool operator<(const Data rhs) const { return dis < rhs.dis; }
  inline Data operator+(const Data rhs) const {
    if (u == 0) return rhs;
    if (rhs.u == 0) return *this;
    Data res = std::max(*this, rhs);
    res = std::max(res, std::max(Data(u, rhs.v), Data(v, rhs.u)));
    res = std::max(res, std::max(Data(u, rhs.u), Data(v, rhs.v)));
    return res;
  }
} dp[N][2];

inline ll merge(const Data& a, const Data& b) {
  if (a.u == 0 || b.u == 0) return 0;
  return std::max(std::max(cd(a.u, b.u), cd(a.v, b.v)),
                  std::max(cd(a.u, b.v), cd(a.v, b.u)));
}

inline bool cmp(int a, int b) {
  int k1 = (a < 0) ? dfo[-a] : dfi[a];
  int k2 = (b < 0) ? dfo[-b] : dfi[b];
  return k1 < k2;
}

inline void dfs(int u, int fa) {
  st[0][dfn[u] = ++cnt] = u;
  dfi[u] = ++df;
  nw[u] += dis[u];
  for (int i = G.heads[u], v; i; i = G.e[i].nxt)
    if ((v = G.e[i].v) != fa) {
      dis[v] = dis[u] + G.e[i].w, dep[v] = dep[u] + 1;
      dfs(v, u);
      st[0][++cnt] = u;
    }
  dfo[u] = ++df;
}

inline void pre() {
  for (int k = 1, j = 1; k < cnt; k <<= 1, ++j)
    for (int i = 1; i + k <= cnt; ++i) st[j][i] = cmi(st[j - 1][i], st[j - 1][i + k]);
}

inline int getLca(int u, int v) {
  u = dfn[u], v = dfn[v];
  if (v < u) std::swap(u, v);
  int k = lg[v - u + 1];
  return cmi(st[k][u], st[k][v - (1 << k) + 1]);
}

inline void solve(ll k) {
  tot = 0;
  for (int i = 1; i <= ::cnt[0]; ++i) node[++tot] = q[0][i];
  for (int i = 1; i <= ::cnt[1]; ++i) node[++tot] = q[1][i];
  std::sort(node + 1, node + tot + 1, cmp);
  for (int i = 1; i <= tot; ++i) key[node[i]] = true;
  for (int i = 1; i <= tot; ++i) {
    int u = node[i], t = typ[u];
    dp[u][t] = Data(u, u, 0), dp[u][!t] = Data();
  }
  for (int i = 1, lim = tot; i < lim; ++i) {
    int lca = getLca(node[i], node[i + 1]);
    if (!key[lca]) key[lca] = true, node[++tot] = lca, dp[lca][0] = dp[lca][1] = Data();
  }
  for (int i = 1; i <= tot; ++i) key[node[i]] = false;
  for (int i = 1, lim = tot; i <= lim; ++i) node[++tot] = -node[i];
  std::sort(node + 1, node + tot + 1, cmp);
  for (int i = 1; i <= tot; ++i)
    if (node[i] > 0) sta[++tp] = node[i];
    else {
      if (!--tp) continue;
      int u = sta[tp + 1];
      int f = sta[tp];
      ans = std::max(ans, std::max(merge(dp[u][0], dp[f][1]), merge(dp[u][1], dp[f][0])) +
                              k - (dis[f] << 1));
      dp[f][0] = dp[f][0] + dp[u][0];
      dp[f][1] = dp[f][1] + dp[u][1];
    }
}

}  // namespace Tr2

namespace Tr1 {

Graph G, H;

int rt, sum, min, tot;
int siz[N * 2], ffa[N];
bool cut[N * 2];
ll w[N * 2];

inline void insert(int u, int v, ll w) {
  Tr1::H.add(++tot, v, w);
  Tr1::H.add(ffa[u], tot, 0);
  ffa[u] = tot;
}

void build(int u, int fa) {
  for (int i = G.heads[u], v; i; i = G.e[i].nxt)
    if ((v = G.e[i].v) != fa) insert(u, v, G.e[i].w), build(v, u);
}

inline void build() {
  for (int i = 1; i <= n; ++i) ffa[i] = i;
  tot = n, build(1, 0);
}

inline void getRoot(int u, int fa) {
  siz[u] = 1;
  for (int i = H.heads[u], v; i; i = H.e[i].nxt)
    if ((v = H.e[i].v) != fa && !cut[i >> 1]) {
      getRoot(v, u);
      siz[u] += siz[v];
      int tmp = std::max(siz[v], sum - siz[v]);
      if (min > tmp) min = tmp, rt = i;
    }
}

inline void dfs(int u, int fa, const bool dir) {
  if (u <= n) typ[u] = dir, q[dir][++cnt[dir]] = u;
  for (int i = H.heads[u], v; i; i = H.e[i].nxt)
    if ((v = H.e[i].v) != fa && !cut[i >> 1]) w[v] = w[u] + H.e[i].w, dfs(v, u, dir);
}

inline void solve(int u, int pres = tot) {
  if (pres == 1) return;
  sum = pres;
  min = 0x3f3f3f3f;
  getRoot(u, 0);
  int st = H.e[rt].v, ed = H.e[rt ^ 1].v;
  cut[rt >> 1] = true;
  cnt[0] = cnt[1] = 0, w[st] = w[ed] = 0;
  dfs(st, 0, false), dfs(ed, 0, true);
  for (int i = 1; i <= cnt[0]; ++i) nw[q[0][i]] += w[q[0][i]];
  for (int i = 1; i <= cnt[1]; ++i) nw[q[1][i]] += w[q[1][i]];
  Tr2::solve(H.e[rt].w);
  for (int i = 1; i <= cnt[0]; ++i) nw[q[0][i]] -= w[q[0][i]];
  for (int i = 1; i <= cnt[1]; ++i) nw[q[1][i]] -= w[q[1][i]];
  int tmp = siz[ed];
  solve(st, siz[st]), solve(ed, tmp);
}

}  // namespace Tr1

int main() {
#ifndef ONLINE_JUDGE
#ifdef LOCAL
  freopen64("/tmp/CodeTmp/testdata.in", "r", stdin);
  freopen64("/tmp/CodeTmp/testdata.out", "w", stdout);
#else
  freopen("P4220 [WC2018]通道.in", "r", stdin);
  freopen("P4220 [WC2018]通道.out", "w", stdout);
#endif
#endif

  read(n);
  lg[0] = -1;
  for (int i = 1; i <= n * 2; ++i) lg[i] = lg[i >> 1] + 1;
  ll w;
  for (int i = 1, u, v; i < n; ++i) {
    read(u), read(v), read(w);
    Tr1::G.add(u, v, w);
  }
  for (int i = 1, u, v; i < n; ++i) {
    read(u), read(v), read(w);
    Tr2::G.add(u, v, w);
  }
  for (int i = 1, u, v; i < n; ++i) {
    read(u), read(v), read(w);
    Tr3::G.add(u, v, w);
  }
  Tr3::dfs(1, 0), Tr3::pre();
  Tr2::dfs(1, 0), Tr2::pre();
  Tr1::build(), Tr1::solve(1);
  printf("%lld", ans);
  return 0;
}